/**
 * 
 */
package com.demo2do.fms.scheduler.service.impl;

import java.io.File;
import java.io.Writer;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.output.FileWriterWithEncoding;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.demo2do.core.entity.exception.BusinessException;
import com.demo2do.core.persistence.annotation.Dao;
import com.demo2do.core.utils.StringUtils;
import com.demo2do.fms.scheduler.dao.fms.AppointmentDao;
import com.demo2do.fms.scheduler.dao.fms.FmsJdbcSupport;
import com.demo2do.fms.scheduler.dao.fms.UserDao;
import com.demo2do.fms.scheduler.entity.appointment.DriverAccumulatedMileageSearch;
import com.demo2do.fms.scheduler.entity.appointment.DriverCostAppointment;
import com.demo2do.fms.scheduler.entity.appointment.DriverCostSearch;
import com.demo2do.fms.scheduler.entity.appointment.DriverMileageAppointment;
import com.demo2do.fms.scheduler.entity.appointment.TransportRevenueAppointment;
import com.demo2do.fms.scheduler.entity.appointment.TransportRevenueScheduleSearch;
import com.demo2do.fms.scheduler.entity.appointment.VehicleAccumulatedMileageSearch;
import com.demo2do.fms.scheduler.entity.appointment.VehicleMileageAppointment;
import com.demo2do.fms.scheduler.service.AppointmentWriter;
import com.demo2do.fms.scheduler.util.CsvUtils;

/**
 *
 * @author Ark
 *
 */
@Service("appointmentWriter")
public class AppointmentWriterImpl implements AppointmentWriter {
	
	private static final Logger logger = LoggerFactory.getLogger(AppointmentWriterImpl.class);

	@Value("#{config['appointment.upperlimit']}")
    private Integer upperLimit;
	
	@Value("#{config['appointment.lowerlimit']}")
    private Integer lowerLimit;
	
    @Value("#{config['appointment.page.size']}")
    private Integer pageSize;
    
    @Value("#{config['appointment.csv.path']}")
    private String csvPath;
    
    @Value("#{config['appointment.csv.url']}")
    private String csvUrl;
    
    @Autowired
    private FmsJdbcSupport fmsJdbcSupport;
	
	@Dao
	private AppointmentDao appointmentDao;
	
	@Dao
	private UserDao userDao;
	
	/* (non-Javadoc)
	 * @see com.demo2do.fms.scheduler.service.AppointmentWriter#auditVehicleMileage(com.demo2do.fms.scheduler.entity.appointment.VehicleMileageAppointment)
	 */
	public void auditVehicleMileage(VehicleMileageAppointment appointment) {
	    
	    try {
            
	        Long operator = userDao.get("super").getId();
	        VehicleAccumulatedMileageSearch search = new VehicleAccumulatedMileageSearch(appointment);
	        Map<String, Object> parameters = search.buildParameters();
	        int totals = fmsJdbcSupport.queryForInt(search.buildCountTemplate(), parameters);
	        
	        if (totals > upperLimit) {
	            appointmentDao.update(appointment.reject("导出条数超出上限", operator));
	        } else if (totals < lowerLimit) {
	            appointmentDao.update(appointment.reject("导出条数低于下限", operator));
	        } else {
	            appointmentDao.update(appointment.adopt(operator));
	        }
	        
        } catch (Exception e) {
            logger.error("#auditVehicleMileage() - code=[{}] audit failed, exception={}", appointment.getCode(), e);
        }
        
	}
	
	/* (non-Javadoc)
	 * @see com.demo2do.fms.scheduler.service.AppointmentWriter#startVehicleMileage(com.demo2do.fms.scheduler.entity.appointment.VehicleMileageAppointment)
	 */
	public void startVehicleMileage(VehicleMileageAppointment appointment) {
	    Long operator = userDao.get("super").getId();
	    appointmentDao.update(appointment.start(operator));
	}
	
	/* (non-Javadoc)
	 * @see com.demo2do.fms.scheduler.service.AppointmentWriter#exportVehicleMileage(com.demo2do.fms.entity.report.VehicleMileageAppointment)
	 */
	public void exportVehicleMileage(VehicleMileageAppointment appointment) {
        
        Long operator = userDao.get("super").getId();
        
        try {
            
            // 1. search by page
            VehicleAccumulatedMileageSearch search = new VehicleAccumulatedMileageSearch(appointment);
            Map<String, Object> parameters = search.buildParameters();
            
            int totals = fmsJdbcSupport.queryForInt(search.buildCountTemplate(), parameters);
            int totalPage = (totals + (pageSize - 1)) / pageSize;
            
            String[] titles = {"运输公司", "驳运车车牌", "调度指令组号", "出发地", "目的地", "行驶公里数", "重载公里数", "重载率", "空载公里数", "空载率", "车队", "路桥费", "油费", "其他费用", "内部加油量"};
            
            for (int page = 0; page < totalPage; page++) {

                Integer beginIndex = page * pageSize + 1;
                search.setBeginIndex(beginIndex);
                
                Integer endIndex = (page + 1) * pageSize;
                search.setEndIndex(endIndex);
                
                List<String[]> lines = new LinkedList<String[]>();
                if (page == 0) {
                    lines.add(titles);
                }
                List<String[]> result = fmsJdbcSupport.queryForList(search.buildSentenceTemplate(), parameters, search.buildRowMapper());
                lines.addAll(result);

                // 2. write to csv_file
                String savePath = csvPath + appointment.getCode() + ".csv";
                File csvFile = new File(savePath);
                Writer writer = new FileWriterWithEncoding(csvFile, "GBK", true);
                CsvUtils.write(lines, writer);
                
            }
            
            // 3. handle appointment success
            String saveUrl = csvUrl + appointment.getCode() + ".csv";
            appointmentDao.update(appointment.success(saveUrl, operator));
            
        } catch (Exception e) {
            appointmentDao.update(appointment.fail(operator));
            logger.error("#exportVehicleMileage() - code=[{}] occur exception=[{}]", appointment.getCode(), e);
        }
            
    }
	
	/* (non-Javadoc)
	 * @see com.demo2do.fms.scheduler.service.AppointmentWriter#expiredVehicleMileage(com.demo2do.fms.scheduler.entity.appointment.VehicleMileageAppointment)
	 */
	public void expireVehicleMileage(VehicleMileageAppointment appointment) {
	    
	    try {
            
	        Long operator = userDao.get("super").getId();
	        
	        this.deleteFile(appointment.getUrl());
	        
	        appointmentDao.update(appointment.expire(operator));
	        
        } catch (Exception e) {
            logger.error("#exportVehicleMileage() - code=[{}] occur exception=[{}]", appointment.getCode(), e);
        }
	    
	}
	
	/* (non-Javadoc)
	 * @see com.demo2do.fms.scheduler.service.AppointmentWriter#auditDriverMileage(com.demo2do.fms.scheduler.entity.appointment.DriverMileageAppointment)
	 */
	public void auditDriverMileage(DriverMileageAppointment appointment) {
	    
        try {
            
            Long operator = userDao.get("super").getId();
            DriverAccumulatedMileageSearch search = new DriverAccumulatedMileageSearch(appointment);
            Map<String, Object> parameters = search.buildParameters();
            int totals = fmsJdbcSupport.queryForInt(search.buildCountTemplate(), parameters);
            
            if (totals > upperLimit) {
                appointmentDao.update(appointment.reject("导出条数超出上限", operator));
            } else if (totals < lowerLimit) {
                appointmentDao.update(appointment.reject("导出条数低于下限", operator));
            } else {
                appointmentDao.update(appointment.adopt(operator));
            }
            
        } catch (Exception e) {
            logger.error("#auditDriverMileage() - code=[{}] audit failed, exception={}", appointment.getCode(), e);
        }
	    
	}
	
	/* (non-Javadoc)
	 * @see com.demo2do.fms.scheduler.service.AppointmentWriter#startDriverMileage(com.demo2do.fms.scheduler.entity.appointment.DriverMileageAppointment)
	 */
	public void startDriverMileage(DriverMileageAppointment appointment) {
	    Long operator = userDao.get("super").getId();
        appointmentDao.update(appointment.start(operator));
	}
	
	/* (non-Javadoc)
	 * @see com.demo2do.fms.scheduler.service.AppointmentWriter#exportDriverMileage(com.demo2do.fms.scheduler.entity.appointment.DriverMileageAppointment)
	 */
	public void exportDriverMileage(DriverMileageAppointment appointment) {
	    
	    Long operator = userDao.get("super").getId();
        
        try {
            
            // 1. search by page
            DriverAccumulatedMileageSearch search = new DriverAccumulatedMileageSearch(appointment);
            Map<String, Object> parameters = search.buildParameters();
            
            int totals = fmsJdbcSupport.queryForInt(search.buildCountTemplate(), parameters);
            int totalPage = (totals + (pageSize - 1)) / pageSize;
            
            String[] titles = {"驾驶员", "公司名称", "内部调度指令", "调度日期", "驳运车车牌", "起始地", "目的地", "重载公里数", "空载公里数", "行驶公里数", "重载工资", "空载工资", "总工资"};
            
            for (int page = 0; page < totalPage; page++) {

                Integer beginIndex = page * pageSize + 1;
                search.setBeginIndex(beginIndex);
                
                Integer endIndex = (page + 1) * pageSize;
                search.setEndIndex(endIndex);
                
                List<String[]> lines = new LinkedList<String[]>();
                if (page == 0) {
                    lines.add(titles);
                }
                List<String[]> result = fmsJdbcSupport.queryForList(search.buildSentenceTemplate(), parameters, search.buildRowMapper());
                lines.addAll(result);

                // 2. write to csv_file
                String savePath = csvPath + appointment.getCode() + ".csv";
                File csvFile = new File(savePath);
                Writer writer = new FileWriterWithEncoding(csvFile, "GBK", true);
                CsvUtils.write(lines, writer);
                
            }
            
            // 3. handle appointment success
            String saveUrl = csvUrl + appointment.getCode() + ".csv";
            appointmentDao.update(appointment.success(saveUrl, operator));
            
        } catch (Exception e) {
            appointmentDao.update(appointment.fail(operator));
            logger.error("#exportDriverMileage() - code=[{}] occur exception=[{}]", appointment.getCode(), e);
        }
	    
	}
	
	/* (non-Javadoc)
	 * @see com.demo2do.fms.scheduler.service.AppointmentWriter#expireDriverMileage(com.demo2do.fms.scheduler.entity.appointment.DriverMileageAppointment)
	 */
	public void expireDriverMileage(DriverMileageAppointment appointment) {
	    
	    try {
            
            Long operator = userDao.get("super").getId();
            
            this.deleteFile(appointment.getUrl());
            
            appointmentDao.update(appointment.expire(operator));
            
        } catch (Exception e) {
            logger.error("#expireDriverMileage() - code=[{}] occur exception=[{}]", appointment.getCode(), e);
        }
	    
	}
	
	/* (non-Javadoc)
	 * @see com.demo2do.fms.scheduler.service.AppointmentWriter#auditTransportRevenue(com.demo2do.fms.scheduler.entity.appointment.TransportRevenueAppointment)
	 */
	public void auditTransportRevenue(TransportRevenueAppointment appointment) {
	    
	    try {
            
	        Long operator = userDao.get("super").getId();
	        TransportRevenueScheduleSearch search = new TransportRevenueScheduleSearch(appointment);
	        Map<String, Object> parameters = search.buildParameters();
	        int totals = fmsJdbcSupport.queryForInt(search.buildCountTemplate(), parameters);
	        
	        if (totals > upperLimit) {
                appointmentDao.update(appointment.reject("导出条数超出上限", operator));
            } else if (totals < lowerLimit) {
                appointmentDao.update(appointment.reject("导出条数低于下限", operator));
            } else {
                appointmentDao.update(appointment.adopt(operator));
            }
            
        } catch (Exception e) {
            logger.error("#auditTransportRevenue() - code=[{}] audit failed, exception={}", appointment.getCode(), e);
        }
	    
	}
	
	/* (non-Javadoc)
	 * @see com.demo2do.fms.scheduler.service.AppointmentWriter#startTransportRevenue(com.demo2do.fms.scheduler.entity.appointment.TransportRevenueAppointment)
	 */
	public void startTransportRevenue(TransportRevenueAppointment appointment) {
	    Long operator = userDao.get("super").getId();
        appointmentDao.update(appointment.start(operator));
	}
	
	/* (non-Javadoc)
	 * @see com.demo2do.fms.scheduler.service.AppointmentWriter#exportTransportRevenue(com.demo2do.fms.scheduler.entity.appointment.TransportRevenueAppointment)
	 */
	public void exportTransportRevenue(TransportRevenueAppointment appointment) {
	    
        Long operator = userDao.get("super").getId();
        
        try {
            
            // 1. search by page
            TransportRevenueScheduleSearch search = new TransportRevenueScheduleSearch(appointment);
            Map<String, Object> parameters = search.buildParameters();
            
            int totals = fmsJdbcSupport.queryForInt(search.buildCountTemplate(), parameters);
            int totalPage = (totals + (pageSize - 1)) / pageSize;
            logger.info("#exportTransportRevenue() - appointment code [{}], search totals is [{}], totalPage is [{}], pageSize is [{}]", appointment.getCode(), totals, totalPage, pageSize);
            String[] titles = {"驳运车", "订单号", "调度单号", "派车单号", "预计发车时间", "调度指令时间", "运输方式", "委托方", "承运方", "最终客户", "制造商", "出发地", "目的地", "回单日期", 
                    "可结算标识", "总收入", "费率", "结算公里数", "是否暂估", "是否开票", "开票日期", "是否销单", "车型大类", "颜色", "VIN码", "承接车队", "外结费用", "外结单价", "外结公里数", "外结是否暂估", 
                    "FMS公司代码", "原始收入订单", "VIN码", "调度单号", "运输成本", "运输收入", "SESSION_ID"};
            
            for (int page = 0; page < totalPage; page++) {

                Integer beginIndex = page * pageSize + 1;
                search.setBeginIndex(beginIndex);
                
                Integer endIndex = (page + 1) * pageSize;
                search.setEndIndex(endIndex);
                
                logger.info("#exportTransportRevenue() current loop page is [{}], the beginIndex is [{}], and the endIndex is [{}]", page, beginIndex, endIndex);
                
                List<String[]> lines = new LinkedList<String[]>();
                if (page == 0) {
                    lines.add(titles);
                }
                List<String[]> result = fmsJdbcSupport.queryForList(search.buildSentenceTemplate(), parameters, search.buildRowMapper());
                lines.addAll(result);

                // 2. write to csv_file
                String savePath = csvPath + appointment.getCode() + ".csv";
                File csvFile = new File(savePath);
                boolean exists = csvFile.exists();
                Writer writer = new FileWriterWithEncoding(csvFile, "GBK", true);
                CsvUtils.write(lines, writer);
                logger.info("#exportTransportRevenue() loop write csv file, file name is [{}], exists status is [{}]", savePath, exists);
            }
            
            // 3. handle appointment success
            String saveUrl = csvUrl + appointment.getCode() + ".csv";
            appointmentDao.update(appointment.success(saveUrl, operator));
            
        } catch (Exception e) {
            appointmentDao.update(appointment.fail(operator));
            logger.error("#exportTransportRevenue() - code=[{}] occur exception=[{}]", appointment.getCode(), e);
        }
	    
	}
	
	/* (non-Javadoc)
	 * @see com.demo2do.fms.scheduler.service.AppointmentWriter#expireTransportRevenue(com.demo2do.fms.scheduler.entity.appointment.TransportRevenueAppointment)
	 */
	public void expireTransportRevenue(TransportRevenueAppointment appointment) {
	    
	    try {
            
            Long operator = userDao.get("super").getId();
            
            this.deleteFile(appointment.getUrl());
            
            appointmentDao.update(appointment.expire(operator));
            
        } catch (Exception e) {
            logger.error("#expireTransportRevenue() - code=[{}] occur exception=[{}]", appointment.getCode(), e);
        }
	    
	}
	
	/* (non-Javadoc)
	 * @see com.demo2do.fms.scheduler.service.AppointmentWriter#auditDriverCost(com.demo2do.fms.scheduler.entity.appointment.DriverCostAppointment)
	 */
	public void auditDriverCost(DriverCostAppointment appointment) {
	    
	    try {
            
	        Long operator = userDao.get("super").getId();
	        DriverCostSearch search = new DriverCostSearch(appointment);
	        Map<String, Object> parameters = search.buildParameters();
	        int totals = fmsJdbcSupport.queryForInt(search.buildCountTemplate(), parameters);
	        
	        if (totals > upperLimit) {
                appointmentDao.update(appointment.reject("导出条数超出上限", operator));
            } else if (totals < lowerLimit) {
                appointmentDao.update(appointment.reject("导出条数低于下限", operator));
            } else {
                appointmentDao.update(appointment.adopt(operator));
            }
            
        } catch (Exception e) {
            logger.error("#auditDriverCost() - code=[{}] audit failed, exception={}", appointment.getCode(), e);
        }
	    
	}
	
	/* (non-Javadoc)
	 * @see com.demo2do.fms.scheduler.service.AppointmentWriter#startDriverCost(com.demo2do.fms.scheduler.entity.appointment.DriverCostAppointment)
	 */
	public void startDriverCost(DriverCostAppointment appointment) {
	    Long operator = userDao.get("super").getId();
        appointmentDao.update(appointment.start(operator));
	}
	
	/* (non-Javadoc)
	 * @see com.demo2do.fms.scheduler.service.AppointmentWriter#exportDriverCost(com.demo2do.fms.scheduler.entity.appointment.DriverCostAppointment)
	 */
	public void exportDriverCost(DriverCostAppointment appointment) {
	    
        Long operator = userDao.get("super").getId();
        
        try {
            
            // 1. search by page
            DriverCostSearch search = new DriverCostSearch(appointment);
            Map<String, Object> parameters = search.buildParameters();
            
            int totals = fmsJdbcSupport.queryForInt(search.buildCountTemplate(), parameters);
            int totalPage = (totals + (pageSize - 1)) / pageSize;
            
            String[] titles = {"驳运车号", "派车单号", "调度指令组号", "主驾姓名", "第一副驾驶员", "报销日期", "报销单号", "起始装卸地", "目的装卸地", "商品车数量", "商品车明细",
                    "行驶公里数", "路桥费", "外部油费", "内部加油贴现", "交通费（夜进夜出）", "广告费", "短驳补贴", "提车费用", "交车费用", "冬季油差补贴", "通讯费补贴", "延伸公里数",
                    "多点装车补贴", "多点卸车补贴", "银行取款手续费", "高速补贴", "停车补贴", "带车补贴", "其他费用", "油价补贴", "油耗补贴", "洗车费", "住宿补贴", "摆渡费", "轮胎补贴（冻结）",
                    "副驾带车费用", "线路包干费", "制单人", "报销人"};
            
            for (int page = 0; page < totalPage; page++) {

                Integer beginIndex = page * pageSize + 1;
                search.setBeginIndex(beginIndex);
                
                Integer endIndex = (page + 1) * pageSize;
                search.setEndIndex(endIndex);
                
                List<String[]> lines = new LinkedList<String[]>();
                if (page == 0) {
                    lines.add(titles);
                }
                List<String[]> result = fmsJdbcSupport.queryForList(search.buildSentenceTemplate(), parameters, search.buildRowMapper());
                lines.addAll(result);

                // 2. write to csv_file
                String savePath = csvPath + appointment.getCode() + ".csv";
                File csvFile = new File(savePath);
                Writer writer = new FileWriterWithEncoding(csvFile, "GBK", true);
                CsvUtils.write(lines, writer);
                
            }
            
            // 3. handle appointment success
            String saveUrl = csvUrl + appointment.getCode() + ".csv";
            appointmentDao.update(appointment.success(saveUrl, operator));
            
        } catch (Exception e) {
            appointmentDao.update(appointment.fail(operator));
            logger.error("#exportDriverCost() - code=[{}] occur exception=[{}]", appointment.getCode(), e);
        }
	    
	}
	
	/* (non-Javadoc)
	 * @see com.demo2do.fms.scheduler.service.AppointmentWriter#expireDriverCost(com.demo2do.fms.scheduler.entity.appointment.DriverCostAppointment)
	 */
	public void expireDriverCost(DriverCostAppointment appointment) {
	    
	    try {
            
            Long operator = userDao.get("super").getId();
            
            this.deleteFile(appointment.getUrl());
            
            appointmentDao.update(appointment.expire(operator));
            
        } catch (Exception e) {
            logger.error("#expireDriverCost() - code=[{}] occur exception=[{}]", appointment.getCode(), e);
        }
	    
	}
	
	/**
     * 删除csv文件
     * 
     * @param url
     */
    private void deleteFile(String url) {
        
        String filename = FilenameUtils.getName(url);
        String pathname = StringUtils.connect(csvPath, "/", filename);
        File csvFile = new File(pathname);
        
        if (!csvFile.exists()) {
            throw BusinessException.newInstance("500", "文件不存在");
        }
        
        FileUtils.deleteQuietly(csvFile);
            
    }
	
}
